package com.sailing.xjpb.dict.service.impl;

import com.sailing.xjpb.common.EJBGenerator;
import com.sailing.xjpb.common.SailingAssert;
import com.sailing.xjpb.common.SailingConstants;
import com.sailing.xjpb.common.exception.BusinessException;
import com.sailing.xjpb.dict.entity.bo.DictionaryBO;
import com.sailing.xjpb.dict.entity.po.DictionaryPO;
import com.sailing.xjpb.dict.repository.DictionaryRepository;
import com.sailing.xjpb.dict.service.DictionaryService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.jpa.domain.Specification;

import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * 枚举公共服务API-为各服务间提供枚举查询、翻译等功能
 *
 * @author YaoWei
 * createDate: 2020-12-08
 */
@Slf4j
public class DictionaryServiceImpl implements DictionaryService {

    public static final String TYPE_NOT_NULL = "枚举类型不能为空！";
    @Autowired
    DictionaryRepository dictionaryRepository;

    @Autowired
    private DictionaryService dictionaryService;

    @Override
    @Cacheable(value = SailingConstants.CACHE_DICTIONARY, key = "'queryByType_' + #type", unless = "#result == " +
            "null")
    public List<DictionaryBO> queryByType(String type) {
        try {
            SailingAssert.notNull(type, TYPE_NOT_NULL);
            List<DictionaryPO> dictionaryPOList = dictionaryRepository.findAllByTypeAndEnabledOrderByOrderAsc(type,
                    SailingConstants.BOOLEAN_TRUE);
            return EJBGenerator.convert(dictionaryPOList, DictionaryBO.class);
        } catch (Exception e) {
            log.error("根据枚举类型查询枚举信息失败！type={}", type);
            throw BusinessException.businessError("根据枚举类型查询枚举信息失败！", e);
        }
    }

    @Override
    public DictionaryBO queryByTypeAndCode(String type, String code) {
        SailingAssert.notNull(type, TYPE_NOT_NULL);
        SailingAssert.notNull(code, "枚举code不能为空！");
        try {
            // 从缓存中查找
            List<DictionaryBO> dictionaryBOS = dictionaryService.queryByType(type);
            Optional<DictionaryBO> dictionaryBO = dictionaryBOS.stream()
                    .filter(dict -> StringUtils.equals(dict.getCode(), code)).findFirst();
            return dictionaryBO.orElse(null);
        } catch (Exception e) {
            log.error("根据枚举类型和code查询枚举信息失败！type={}|code={}", type, code);
            throw BusinessException.businessError("根据枚举类型和code查询枚举信息失败！", e);
        }
    }

    @Override
    public DictionaryBO queryByTypeAndName(String type, String name) {
        SailingAssert.notNull(type, TYPE_NOT_NULL);
        SailingAssert.notNull(name, "枚举name不能为空！");
        try {
            // 从缓存中查找
            List<DictionaryBO> dictionaryBOS = dictionaryService.queryByType(type);
            Optional<DictionaryBO> dictionaryBO = dictionaryBOS.stream()
                    .filter(dict -> StringUtils.equals(dict.getName(), name)).findFirst();
            return dictionaryBO.orElse(null);
        } catch (Exception e) {
            log.error("根据枚举类型和code查询枚举信息失败！type={}|name={}", type, name);
            throw BusinessException.businessError("根据枚举类型和name查询枚举信息失败！", e);
        }
    }

    @Override
    public DictionaryBO queryByLabelTypeAndLabelLocation(String labelType, String labelLocation) {
        try {
            Specification<DictionaryPO> spec = (root, query, cb) -> {
                List<Predicate> predicates = new ArrayList<>();
                predicates.add(cb.equal(root.get("labelType"), labelType));
                predicates.add(cb.equal(root.get("labelLocation"), labelLocation));
                return query.where(predicates.toArray(new Predicate[0])).getRestriction();
            };
            Optional<DictionaryPO> dictionaryPO = dictionaryRepository.findOne(spec);
            return EJBGenerator.convert(dictionaryPO.orElse(null), DictionaryBO.class);
        } catch (Exception e) {
            log.error("根据labelType和labelLocation查询枚举信息失败！labelType={}, labelLocation={}", labelType, labelLocation);
            throw BusinessException.businessError("根据labelType和labelLocation查询枚举信息失败！", e);
        }
    }

    @Override
    public DictionaryBO queryById(String id) {
        SailingAssert.notNull(id, "枚举ID不能为空！");
        Optional<DictionaryPO> dictionaryPO = dictionaryRepository.findById(id);
        return EJBGenerator.convert(dictionaryPO.orElse(null), DictionaryBO.class);
    }

    @Cacheable(value = SailingConstants.CACHE_DICTIONARY, key = "'queryByPId_' + #pId", unless = "#result == null")
    @Override
    public List<DictionaryBO> queryByPId(String pId) {
        try {
            List<DictionaryPO> dictionaryPOS = dictionaryRepository.findAllByPid(pId);
            return EJBGenerator.convert(dictionaryPOS, DictionaryBO.class);
        } catch (Exception e) {
            log.error("根据pId查询枚举信息失败！pId={}", pId);
            throw BusinessException.businessError("根据pId查询枚举信息失败！", e);
        }
    }

    @Cacheable(value = SailingConstants.CACHE_DICTIONARY, key = "'queryByTypeAndPId_' +#type +'_' + #pId", unless = "#result == null")
    @Override
    public List<DictionaryBO> queryByTypeAndPId(String type, String pId) {
        try {
            List<DictionaryPO> dictionaryPOS = dictionaryRepository.findAllByTypeAndPidOrderByOrder(type, pId);
            return EJBGenerator.convert(dictionaryPOS, DictionaryBO.class);
        } catch (Exception e) {
            log.error("根据枚举类型和pId查询枚举信息失败！type={}|pId={}", type, pId);
            throw BusinessException.businessError("根据枚举类型和pId查询枚举信息失败！", e);
        }
    }

    @Override
    public void recursionQueryByTypeAndPId(String type, String pId, List<DictionaryBO> dictionaryBOList) {
        try {
            List<DictionaryBO> convert = dictionaryService.queryByTypeAndPId(type, pId);
            dictionaryBOList.addAll(convert);
            for (DictionaryBO dictionaryBO : convert) {
                String leaf = dictionaryBO.getLeaf();
                if (SailingConstants.isFalse(leaf)) {
                    recursionQueryByTypeAndPId(type, dictionaryBO.getId(), dictionaryBOList);
                }
            }
        } catch (Exception e) {
            log.error("recursionQueryByTypeAndPId根据枚举类型和pId查询枚举信息失败！type={}|pId={}", type, pId);
            throw BusinessException.businessError("根据枚举类型和pId查询枚举信息失败！", e);
        }
    }

    @Override
    public String translateData(String code, String type) {
        if (StringUtils.isBlank(code)) {
            return code;
        }
        try {
            DictionaryBO dictionaryBO = queryByTypeAndCode(type, code);
            return dictionaryBO != null ? dictionaryBO.getName() : code;
        } catch (Exception e) {
            log.error("根据code和枚举类型翻译枚举名称失败！code={}|type={}", code, type);
            throw BusinessException.businessError("根据code和枚举类型翻译枚举名称失败！", e);
        }
    }

}
